<template>
  <el-form
    ref="formBody"
    :label-width="labelWidth + 'px'"
    :model="source"
    :label-position="position"
    :rules="rules"
    class="formContent"
  >
    <el-row :gutter="24">
      <el-col
        v-for="item in controlList"
        :key="item.Key+'_'+ item.state"
        :span="item.Column.ColSpan"
        :class="isHidden(item)"
      >
        <el-form-item :label="item.Label" :prop="item.Column.Name">
          <span
            slot="error"
            slot-scope="e"
            :class="e.error.startsWith('0,') ? 'warn' : 'error'"
          >{{ e.error.substring(2) }}</span>
          <userControl
            :key="item.Key"
            v-model="source[item.Column.Name]"
            :link-biz-pk="linkBizPk"
            :control="item.Column"
            :state="item.state"
            :col-id="item.Key"
            :table="table"
            :readonly="isReadonly(item.Key)"
            :is-watch="isWatch(item.Key)"
            :source="source"
            @change="controlChange"
          />
        </el-form-item>
      </el-col>
    </el-row>
  </el-form>
</template>

<script>
import { ControlType } from '@/customForm/config/formConfig'
import userControl from './userControl.vue'
export default {
  components: {
    userControl
  },
  props: {
    labelWidth: {
      type: Number,
      default: 120
    },
    readonly: {
      type: Boolean,
      default: false
    },
    linkBizPk: {
      type: String,
      default: null
    },
    power: {
      type: Object,
      default: null
    },
    table: {
      type: Object,
      default: null
    },
    source: {
      type: Object,
      default: null
    },
    watchCol: {
      type: Object,
      default: null
    },
    defState: {
      type: Object,
      default: null
    }
  },
  data() {
    return {
      ControlType,
      controlList: [],
      rules: [],
      position: 'left',
      ver: 1
    }
  },
  watch: {
    table: {
      handler(val) {
        if (val) {
          this.reset()
        }
      },
      immediate: true
    },
    defState: {
      handler(val) {
        if (val) {
          this.$nextTick(this.resetState)
        }
      },
      deep: true,
      immediate: false
    }
  },
  mounted() {},
  methods: {
    isWatch(key) {
      if (this.watchCol == null) {
        return false
      }
      return this.watchCol[key] != null
    },
    isHidden(col) {
      return col.state === 1 || col.Column.ColType === ControlType.hidden.value ? 'hidden' : null
    },
    controlChange(e) {
      this.$emit('change', e)
    },
    isReadonly(key) {
      if (this.readonly) {
        return true
      } else if (this.power == null) {
        return false
      }
      const opt = this.power[key]
      return opt != null && opt === 0
    },
    dataValidator(rule, value, callback) {
      if (value == null) {
        callback()
        return
      }
      const set = rule.sour
      let isSuccess = false
      if (set.RuleType === 1 && rule.pattern != null) {
        isSuccess = rule.pattern.test(value)
      } else if (set.RuleType === 0) {
        if (typeof value !== 'number') {
          value = Number.parseFloat(value)
        }
        if (set.Min == null && set.Max == null) {
          isSuccess = true
        } else {
          if (set.Min != null) {
            isSuccess = set.MinIsEqual ? value >= set.Min : value > set.Min
          }
          if (set.Max != null) {
            isSuccess = set.MaxIsEqual ? value <= set.Max : value < set.Max
          }
        }
      } else if (set.RuleType === 2 && set.MinLen != null) {
        if (typeof value !== 'string') {
          value = value.toString()
        }
        isSuccess = set.MinLen <= value.length
      } else {
        callback()
        return
      }
      if (isSuccess) {
        callback()
      } else if (set.IsWarn) {
        callback('0,' + set.Message)
      } else {
        callback(new Error('1,' + set.Message))
      }
    },
    resetState() {
      const list = []
      let isRef = false
      this.controlList.forEach(c => {
        const t = Object.assign({}, c)
        const v = this.defState[c.Key]
        if (v != null && t.state !== v) {
          t.state = v
          isRef = true
        }
        list.push(t)
      })
      if (isRef) {
        this.initRules(this.defState, list)
        this.controlList = list
      }
    },
    initRules(state, controls) {
      const rules = {}
      controls.forEach((c) => {
        const col = c.Column
        if ('state' in c === false) {
          c.state = state[c.Key]
          if (c.state == null) {
            c.state = 0
          }
        }
        if (c.state !== 0) {
          return
        }
        if (
          col.IsNotNull === false &&
          (col.ValidateRule == null || col.ValidateRule.length === 0)
        ) {
          return
        }
        const list = []
        if (col.IsNotNull === true) {
          list.push({
            required: true,
            message: c.Label + '不能为空！',
            trigger: 'blur'
          })
        }
        if (col.ValidateRule != null && col.ValidateRule.length !== 0) {
          col.ValidateRule.forEach((a) => {
            const rule = {
              key: c.Key,
              trigger: 'blur',
              sour: a,
              validator: this.dataValidator
            }
            if (a.RuleType === 1) {
              rule.pattern = new RegExp(a.Regex)
            }
            list.push(rule)
          })
        }
        rules[col.Name] = list
      })
      this.rules = rules
    },
    reset() {
      if (this.table.LabelPosition === 2) {
        this.position = 'right'
      } else if (this.table.LabelPosition === 1) {
        this.position = 'top'
      } else {
        this.position = 'left'
      }
      let list
      if (this.table.Columns != null) {
        if (this.power == null) {
          list = this.table.Columns
        } else {
          list = this.table.Columns.filter(a => this.power[a.Key] !== 2)
        }
        let state = this.defState
        if (state == null) {
          state = {}
        }
        this.initRules(state, list)
        this.controlList = list
      } else {
        this.controlList = []
        this.rules = {}
      }
    },
    validate() {
      return new Promise((resolve, reject) => {
        this.$refs['formBody'].validate((valid, error) => {
          if (valid) {
            resolve(true)
          } else if (this.checkIsWarn(error)) {
            resolve(true)
          } else {
            resolve(false)
          }
        })
      })
    },
    checkIsWarn(error) {
      for (const i in error) {
        const err = error[i]
        const index = err.findIndex(c => !c.message.startsWith('0,'))
        if (index !== -1) {
          return false
        }
      }
      return true
    }
  }
}
</script>
<style scoped>
.el-form-item {
  min-height: 60px;
}
.is-error {
  margin-bottom: 0px !important;
}
.error {
  color: #ff4949;
}
.warn {
  color: #ffba00;
}
.hidden {
  display: none;
}
.is-error:has(.warn) {
  .el-input__inner {
    border-color: #ffba00 !important;
  }
}
</style>
